6. 枚举

枚举

列举,罗列。代表一系列的类型,这些类型有一个非常的明显的特征,就是他们的对象是有限的几个。枚举是 JDK 1.5 之后才有的。枚举类型也是类,原来用 class 声明类,现在用 enum 来声明枚举。

说明

  1. 枚举类型的构造器一定是私有的

  2. 枚举类型的常量对象列表必须在枚举类的首行

  3. 所有枚举类型有一个直接父类 java.lang.Enum 类型,所以不能在继承其他类。 java.lang.Enum 中已经复写了 toString 方法,返回的是常量的名字。

  4. switch… case 增加了对枚举的支持

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.itguigu.com;

public class TestEnumType {
public static void main(String[] args) {
Week monday = Week.Monday;
System.out.println(monday); // 枚举类默认继承自 java.lang.Enum,里面已经重写了 toString, 返回常量名称

switch (monday) {
case Monday:
System.out.println("周一");
break;
default:
System.out.println("未匹配到星期");
break;
}
}
}


/**
* 使用 enum 声明枚举类,默认继承自 java.lang.Enum
* @author rex
*
*/
enum Week{
Monday("星期一", "最难的一天"), // 使用的是有参的构造。且常量对象列表必须在枚举类的首行
Tuesday, // 使用的无参的构造
Wednesday,
Thursday,
Friday,
Saturday,
Sunday;

private String name;
private String desc;

/**
* 无参私有构造,默认就有
*/
private Week() {

}

/**
* 有参数私有构造
* @param name
* @param desc
*/
private Week(String name, String desc) {
this.name = name;
this.desc = desc;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}
}
1
2
Monday
周一

java.lang.Enum中的方法

java.lang.Enum是所有 Java 语言枚举类型的公共基本类。即所有的枚举类型都继承它,不能在继承别的类型。

  1. name(): 返回此枚举常量的名称
  2. ordinal(): 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为0)
  3. int compareTo(x):默认按照枚举对象的顺序排序
  4. API 中没有,编译器自动生成的方法:values(),valueOf(常量名)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package com.itguigu.com;

public class TestEnumType {
public static void main(String[] args) {
Week monday = Week.Monday;
System.out.println(monday); // Monday
System.out.println(monday.name()); // Monday
System.out.println(monday.ordinal()); // 0

Week[] values = Week.values();
for (int i = 0; i < values.length; i++) {
System.out.println(values[i]); // Monday Tuesday Wednesday Thursday Friday Saturday Sunday
}

Week valueOf = Week.valueOf("Monday");
System.out.println(valueOf); // Monday
}
}


/**
* 使用 enum 声明枚举类,默认继承自 java.lang.Enum
* @author rex
*
*/
enum Week{
Monday("星期一", "最难的一天"), // 使用的是有参的构造。且常量对象列表必须在枚举类的首行
Tuesday, // 使用的无参的构造
Wednesday,
Thursday,
Friday,
Saturday,
Sunday;

private String name;
private String desc;

/**
* 无参私有构造,默认就有
*/
private Week() {

}

/**
* 有参数私有构造
* @param name
* @param desc
*/
private Week(String name, String desc) {
this.name = name;
this.desc = desc;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}
}

注解

注解由三部分组成:

  1. 声明注解,既定义注解(绝大部分都是别人定义好的)
  2. 使用注解
  3. 读取注解的信息。我们把读取注解信息的代码称之为 ”注解信息处理流程“。如果没有 “读取注解的信息” 的过程,前两步没有意义。读取注解的代码基本上也是别人写好的。读取注解的信息需要用到 “反射”。

1. 系统预定义的三个基本的注解

@Override:由 JDK 的核心库定义,它由编译器读取,例如 javac.exe。作用是表示方法是一个 “重写” 的方法,让编译器对这个方法的签名进行格式检查,检查是否符合 “重写” 的要求。被 static,final,private 修饰的方式是不能被重写的。

方法重写应该满足的要求:

  1. 方法名和形参列表必须相同

  2. 返回值类型:

    如果是基本数据类型和 void:必须相同

    引用数据类型:返回值应该是小于或者等于的关系(小于【子类】或者等于父类的返回值)

  3. 权限修饰符:大于等于父类的权限修饰符。

  4. 不是被 static,final,private 修饰的方法

@SuppressWarnings: 由 JDK 的核心库定义,它由编译器读取,例如 javac.exe。作用是抑制警告。

@Deprecated: 由 JDK 的核心库定义,它由编译器读取,例如 javac.exe。作用是标识,类,方法,属性已经过时,不建议再使用。

2. 文档注释

@param: 方法必须有行参,有几个行参就写几个。格式为 @param 形参名 行参数据类型 解析

@return:方法的返回值类型必须不是void,且一个方法就只能有一个@return。格式为 @return 返回值类型 解释

@throws:必须方法有 throws 异常才写,且有几个就写几个。格式为 @throws 类型 解释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.itguigu.com;

/**
*
* @author rex
* @version JDK1.8
* @since JDK 1.5
*/
public class TestDoc {
/**
* 主方法
* @param args String[]
*/
public static void main(String[] args) {

}

/**
* 求两个整数的最大值
* @param a int
* @param b int
* @return int 返回 a,b 中的最大值
*/
public static int getMax(int a, int b) {
return a>b?a:b;
}

/**
* 求两个整数的商
* @param a int 被除数
* @param b int 除数
* @return int 商
* @throws RuntimeException 当除数为 0 时会抛出异常
*/
public static int divide(int a, int b)throws RuntimeException {
if (b==0) {
throw new RuntimeException("除数不能为0");
}else {
return a/b;
}
}
}

将注释导出为文档:

3. 单元测试相关

@Test: 加在方法上进行单元测试。被测试的方法的参数必须是 public,且返回值是 void,且无参数的。而且要求方法所在类也是 public 的。

@Before:在每一个 @Test 标记的方法之前运行

@After:在每一个 @Test 标记的方法之后运行

@BeforeClass:在当前类初始化时执行,方法必须是 static 修饰的。只执行一次。

@AfterClass:在所有方法运行之后运行,方法必须是 static 修饰的。只执行一次

目前 ide 都有 Junit 的 jar 包,我们直接添加就行。eclipse 步骤如下:

项目右键 -> Build Path -> Add library -> JUnit -> 选择版本 -> finish

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.itguigu.com;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class TestJunit {
@BeforeClass
public static void init() {
System.out.println("最先执行");
}

@Before
public void test11() {
System.out.println("每个 @Test 执行之前都会打印");
}

@After
public void test11111() {
System.out.println("每个 @Test 执行之后都会打印");
}

@AfterClass
public static void test111() {
System.out.println("最后执行");
}

@Test
public void test1() {
System.out.println("111");
}

@Test
public void test1111() {
System.out.println("222");
}
}

自定义注解和元注解

元注解

元注解:元注解就是注解上面的注解

  1. @Target: 可以指定定义的注解用在什么位置上。位置由 ElementType 枚举的常量对象来指定。
  2. @Retention: 标记注解可以滞留到某个阶段,也就是注解的声明周期。由,RetentionPolicy 常量对象来指定。具体的值有 SOURCE(源代码阶段,默认),CLASS(字节码阶段),RUNTIME(运行时)

  3. @Documented: 标记注解是否可以被 javadoc.exe 读取到 API 中 (不常用)

  4. @Inherited: 标记注解是否能被子类继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.itguigu.com;

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class TestDefineAnnotation {
public static void main(String[] args) {
// 反射
Class clazz = MyClass.class;
MyAnnotation myAnnotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
System.out.println(myAnnotation);
}
}

@MyAnnotation
class MyClass{
@MyAnnotation
public String testField;

@MyAnnotation
public void test() {};
}

/**
* 自定义注解三个步骤:
* 1. 声明注解
* 2. 使用
* 3. 读取
* @author rex
*
*/
@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) // 表明 MyAnnotation 注解可以用在方法,属性和类上
@Retention(RetentionPolicy.RUNTIME) // 将注解声明周期控制到运行时,这样在反射中才能使用
@interface MyAnnotation{

}

配置注解参数

配置参数的赋值

  1. 如果注解声明配置参数,那么在使用这个注解的时候就需要给配置参数赋值。格式为 ”配置参数名=参数值“。
  2. 如果配置参数的个数只有一个,并且名称是 value,那么可以省略 “配置参数名=”。
  3. 如果配置参数有默认值,那么可以不赋值。
  4. 配置参数的类型可以为 八种基本数据类型,String,Class,enum,Annotation,及以上所有类型的数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.itguigu.com;

public class TestAnnotionParam {

}

// 使用注解参数
@A
class B{

}

@interface A{
// String info();

// String value();

String info() default "default value";
}